from PyQt5.QtCore import Qt, QVariant
from PyQt5.QtSql import QSqlQuery,\
                        QSqlTableModel,\
                        QSqlField,\
                        QSqlRecord
from pymonad import Either, Result, Error


def createModel(db, table):
    if ((not isCore(db.db)) and ((table=='DataTypes') or ('Struct' in table))):
        currdb = db.dbcore
        db.models[table] = QSqlTableModel(None, db.dbcore)
    else:
        currdb = db.db
        db.models[table] = QSqlTableModel(None, db.db)
    db.models[table].setTable(table)
    db.models[table].select()
    print('Table {0} from {1} loaded.'.format(table, currdb.databaseName()))
    return Result(True)


def resetModel(db, model):
    model.setTable(model.tableName())
    model.select()


def addRow(db, model, key):
    namefield = model.record(0).fieldName(0)
    f = QSqlField(namefield, QVariant.String)
    f.setValue(key)
    rec = QSqlRecord()
    rec.append(f)
    result = model.insertRecord(-1, rec)
    return result


def removeRow(db, model, key):
    first = model.index(0, 0)
    m = model.match(first, Qt.DisplayRole, key)
    row = m[0].row()
    model.removeRow(row)
    model.select()


def addColumn(db, model, key):
    result = runQuery(db.db, 'ALTER TABLE "{0}" ADD "{1}" TEXT'.format(model.tableName(), key))

    if not result:
        message = 'Unable to add {0} to {1}'.format(key, model.tableName())
        db.errored.emit(message)
    else:
        resetModel(db, model)


def removeColumn(db, model, key):
    # SQLite does not support DROP COLUMN.  Per SQLite documentation
    #   (https://www.sqlitetutorial.net/sqlite-alter-table/), the 
    #   way to drop a column is the following:
    #     1. Create a new table mirroring the original table without the column
    #     2. Copy over all the data from the original table (minus the column)
    #     3. Delete the original table
    #     4. Rename the new table to the original table name

    cols = []
    for col in range(model.columnCount()):
        if not model.headerData(col, Qt.Horizontal)==key:
            cols.append('"' + model.headerData(col, Qt.Horizontal) + '"')
    columns = ','.join(cols)
    oldtable = model.tableName()
    newtable = 'new_' + oldtable

    result = runQuery(db.db, 'CREATE TABLE IF NOT EXISTS "{0}" ({1})'.format(newtable, columns)) >> \
             runQuery(db.db, 'INSERT INTO "{0}"({2}) SELECT {2} FROM "{1}"'.format(newtable, oldtable, columns)) >> \
             runQuery(db.db, 'DROP TABLE "{0}"'.format(oldtable)) >> \
             runQuery(db.db, 'ALTER TABLE "{0}" RENAME TO "{1}"'.format(newtable, oldtable))

    if result == Result(True):
        print('Table Name: {0}'.format(model.tableName()))
        resetModel(db, model)
    else:
        message = result.getValue()
        db.errored.emit(message)


def runQuery(db, sql):
    query = QSqlQuery(db)
    result = query.exec(sql)

    if result:
        if query.isSelect():
            results = []
            while query.next():
                results.append(query.record())
            return Result(results)
        else:
            return Result(True)
    else:
        return Error('Query: {0}\nSize: {4}\nError: {1}\nDB: {2}\nType: {3}'.format(query.lastQuery(), query.lastError().text(), query.lastError().databaseText(), str(query.lastError().type()), str(query.size())))


def isCore(db):
    result = runQuery(db, 'SELECT * FROM Rulebook LIMIT 1')
    print('isCore Result: ')
    print(result.getValue())
    if not isError(result):
        if result.getValue()[0].value('Core')=='True':
            return True
        else:
            return False
    else:
            return False


def isError(result):
    return (result == Error(0))
